/*------------------------------------------------------*/

#ifndef RTMUTEX_H
#define RTMUTEX_H

#include "RtDefines.h"
#include "RtError.h"
#include "RtUtilClasses.h"

class RT_API_EXPORT CRtMutexBase
{
protected:
	CRtMutexBase();
	~CRtMutexBase();

public:
	RtResult Lock();
	RtResult UnLock();
	RtResult TryLock();

	RT_THREAD_MUTEX_T& GetMutexType() { return m_Lock;}

protected:
	RT_THREAD_MUTEX_T m_Lock;
};

/**
 * Mainly copyed from <ACE_Recursive_Thread_Mutex>.
 * <CRtMutexThreadRecursive> allows mutex locking many times in the same threads.
 */
class RT_API_EXPORT CRtMutexThreadRecursive : public CRtMutexBase
{
public:
	CRtMutexThreadRecursive();
	~CRtMutexThreadRecursive();

private:
	// = Prevent assignment and initialization.
	void operator = (const CRtMutexThreadRecursive&);
	CRtMutexThreadRecursive(const CRtMutexThreadRecursive&);
};

class RT_API_EXPORT CRtMutexThread : public CRtMutexBase
{
public:
	CRtMutexThread();
	~CRtMutexThread();

private:
	// = Prevent assignment and initialization.
	void operator = (const CRtMutexThread&);
	CRtMutexThread(const CRtMutexThread&);
};

/**
 *	<CRtMutexNullSingleThread> checks to ensure running on the same thread
 */
class /*RT_API_EXPORT*/ CRtMutexNullSingleThread
{
public:
	CRtMutexNullSingleThread() 
	{
	}

	// this function may be invoked in the different thread.
	~CRtMutexNullSingleThread() 
	{
//		m_Est.EnsureSingleThread();
	}

	RtResult Lock() 
	{
		m_Est.EnsureSingleThread();
		return RT_OK;
	}

	RtResult UnLock() 
	{
		m_Est.EnsureSingleThread();
		return RT_OK;
	}

	RtResult TryLock() 
	{
		m_Est.EnsureSingleThread();
		return RT_OK;
	}

private:
	CRtEnsureSingleThread m_Est;

private:
	// = Prevent assignment and initialization.
	void operator = (const CRtMutexNullSingleThread&);
	CRtMutexNullSingleThread(const CRtMutexNullSingleThread&);
};

// Use <CRtMutexNullSingleThread> instead <CRtMutexNull> to ensure in the single thread.

template <class MutexType>
class /*RT_API_EXPORT*/ CRtMutexGuardT
{
public:
	CRtMutexGuardT(MutexType& aMutex)
		: m_Mutex(aMutex)
		, m_bLocked(FALSE)
	{
		Lock();
	}

	~CRtMutexGuardT()
	{
		UnLock();
	}

	RtResult Lock() 
	{
		RtResult rv = m_Mutex.Lock();
		m_bLocked = RT_SUCCEEDED(rv) ? TRUE : FALSE;
		return rv;
	}

	RtResult UnLock() 
	{
		if (m_bLocked) {
			m_bLocked = FALSE;
			return m_Mutex.UnLock();
		}
		else {
			return RT_OK;
		}
	}

private:
	MutexType& m_Mutex;
	BOOL m_bLocked;

private:
	// = Prevent assignment and initialization.
	void operator = (const CRtMutexGuardT&);
	CRtMutexGuardT(const CRtMutexGuardT&);
};

#endif // !RTMUTEX_H
